package com.atjava.nebula.web.view;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.atjava.jox.JOXManager;
import com.atjava.nebula.core.exception.baseExp.BusinessException;
import com.atjava.nebula.core.exception.baseExp.SystemException;
import com.atjava.nebula.core.service.GenericService;
import com.atjava.nebula.core.service.impl.GenericServiceImpl;
import com.atjava.nebula.core.tablexml.view.Column;
import com.atjava.nebula.core.tablexml.view.Grid;
import com.atjava.nebula.core.tablexml.view.Query;
import com.atjava.nebula.core.tablexml.view.Renderer;
import com.atjava.nebula.core.tablexml.view.Section;
import com.atjava.nebula.core.tablexml.view.Tree;
import com.atjava.nebula.core.tablexml.view.ViewConfig;
import com.atjava.nebula.core.util.func.ClassLoaderUtil;
import com.atjava.nebula.core.util.reflection.ReflectUtil;
import com.atjava.nebula.web.util.PropertyUtils;
import com.atjava.nebula.web.util.XmlViewVariableUtil;

public class XmlViewManager {
	
	public static Class<?> getEntityClass(String catalog,String entity){
		try {
			String entityClassName = PropertyUtils.getProperty(catalog + "." + entity);
			return (Class<?>) Class.forName(entityClassName);
		} catch (Exception e) {
			throw new SystemException(e,"Load entity class by url ["+ catalog + "/" + entity +"].");
		}
	}
	
	public static Column getColumn(Grid grid,String prop){
		
		List<Column> columns = grid.getColumns();
		for (int i = 0; i < columns.size(); i++) {
			Column col = columns.get(i);
			
			if(col.getProperty() != null && prop.endsWith(col.getProperty())){
				return col;
			}
		}

		return null;
	}
	
	@Deprecated
	public static Tree getTree(ViewConfig config,String id){
		return getXmlViewBeanById(config, id, Tree.class);
	}
	
	@Deprecated
	public static Query getQuery(ViewConfig config,String id){
		return getXmlViewBeanById(config, id, Query.class);
	}
	
	@Deprecated
	public static Grid getGrid(ViewConfig config,String id){
		return getXmlViewBeanById(config, id, Grid.class);
	}
	
	public static ViewConfig getXmlViewConfig(String catalog,String xmlview){
		
		ViewConfig config = XmlViewConfiguration.readViewConfig(catalog, xmlview);
		if(config == null){
			throw new SystemException("View config file was not found. catalog:["+catalog+"], xmlview:["+xmlview+"]");
		}
		
		String source = config.getSource();
		
		try {
			
			JOXManager mgr = new JOXManager();
			Document doc = getDocumentFromContext(config.getSource());
			config = mgr.getBean(doc.getRootElement(),ViewConfig.class);
			config.setSource(source);
			
			List<Section> sections = config.getMainView().getSections();
			if(sections == null){
				return config;
			}
			for (int i = 0; i < sections.size(); i++) {
				Section sec = sections.get(i);
				
				//Grid
				Grid grid = sec.getGrid();
				if(grid != null){
					try {	
						XmlViewManager.evalGridColumnDataset(grid);
						
					} catch (BusinessException e) {
						throw new SystemException("Set column dataset data to dataset map.");
					}
					
					if(!config.isHasTreeTable() && grid.isTree()){
						config.setHasTreeTable(true);
					}
				}
				
			}
			
		} catch (Exception e) {
			throw new SystemException(e,"Get view config error. catalog:["+catalog+"], xmlview:["+xmlview+"]");
		}
		
		return config;
	}
	
	private static Document getDocumentFromContext(String source) throws DocumentException {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		String evalSource = source;
		if(request != null){
			evalSource =  XmlViewVariableUtil.evalRequestParamsVariables(request, evalSource);
		}
		return DocumentHelper.parseText(evalSource);
	}
	
	public static <T> T getXmlViewBeanById(ViewConfig config,String id,Class<T> cls){
		T obj = null;
		try {
			JOXManager mgr = new JOXManager();
			Document doc = getDocumentFromContext(config.getSource());
			Element e = (Element)doc.selectSingleNode("//*[@id='"+id+"']");
			obj = (T)mgr.getBean(e,cls);
			
			if(obj instanceof Grid){
				Grid grid = (Grid)obj;
				evalGridColumnDataset(grid);
			}
			
		} catch (Exception e) {
			throw new SystemException("can not convert element [id="+id+"] to "+cls);
		}
		return obj;
	}
	
	public static Element getXmlViewElementById(ViewConfig config,String id){
		Element el = null;
		try {
			Document doc = getDocumentFromContext(config.getSource());
			el = (Element)doc.selectSingleNode("//*[@id='"+id+"']");
		} catch (Exception e) {
			throw new SystemException("can not get element from configuration file. [id="+id+"]");
		}
		return el;
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private static void evalGridColumnDataset(Grid grid) throws BusinessException{
		
		List<Column> columns = grid.getColumns();
		
		for (int i = 0; i < columns.size(); i++) {
			
			Column col = columns.get(i);
			Renderer renderer = col.getRenderer();
			if(renderer != null){
				
				String dataset = renderer.getDataset();
				String entityClassName = PropertyUtils.getProperty(dataset);
				Class<?> entityClass = ClassLoaderUtil.loadClass(entityClassName);
				
				GenericService<?,?> genService = new GenericServiceImpl(entityClass);
				List<?> dataList = genService.getAll();
				
				Map<Object, Object> map = new HashMap<Object, Object>();
				for (int j = 0; j < dataList.size(); j++) {
					Object obj = dataList.get(j);
					Object key = ReflectUtil.getFieldValue(obj, renderer.getKey());
					Object value = ReflectUtil.getFieldValue(obj, renderer.getValue());
					map.put(key, value);
				}
				
				col.setRendererMap(map);
				
			}
		}

	}
	
}
